package mbsl.books;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableItem;

import mbsl.commons.base.ElementController;
import mbsl.main.MainController;
import mbsl.system.Core;
import mbsl.system.Logger;
import mbsl.system.TextProvider;
import mbsl.ui.BarCreator;
import mbsl.ui.dialogs.Options;
import mbsl.ui.interfaces.Listener;

/**
 * The book controller.
 */
public class BookController extends ElementController<Book> {
	private static TextProvider tp = Books.tp.prefix("books");
	
	public BookController(MainController pController) {
		super(pController, Book.class, tp.get("tabTitle"));
		
		setActiveColumn(0);
	}
	@Override
	protected void focusGained() {
		super.focusGained();
		
		MenuItem item = getParent().getMenuBarController().add(tp.get("menu") + "//" + Core.tp.get("ui.menu.options"));
		
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent pE) {
				showOptions();
			}
		});
		
		item.setEnabled(false); // Let's wait until we get some options.
	}
	@Override
	protected void focusLost() {
		super.focusLost();
		
		getParent().getMenuBarController().remove(tp.get("menu"));
	}
	/** 
	 * Opens an edit dialogue for the passed element.
	 * <p>
	 * Because of special functionality in the EditController, if null is passed, a new Game will
	 * be created for the dialogue.
	 */
	protected void editDialog(Book pElement) {
		if (mEditController == null) {
			mEditController = new BookEditController(this, getParent().getWindow());
			
			mEditController.addChangeListener(new Listener() {
				public void alert() {
					/* It's possible there's a way to do this more efficiently, namely refresh just its row, or insert a row if
					 * it's a new item, but the problem is considering ordering.  What if the element has changed what we're ordering
					 * by, or we're ordering by something other than name in the case of a new one?
					 */
					refresh();
				}
			});
		}
		
		mEditController.setElement(pElement);
		
		mEditController.open();
	}
	@Override
	protected void viewDialog(Book pElement) {
		if (mViewController == null) {
			mViewController = new BookViewController(this, getParent().getWindow());
			
			mViewController.addChangeListener(new Listener() {
				@Override
				public void alert() {
					refresh(mViewController.getElement());
				}
			});
		}
		
		mViewController.setElement(pElement);
		
		mViewController.open();
	}
	@Override
	protected void newDialog(Book pElement) {
		// The EditController can create new instances itself, but because if the import folder functionality,
		// we need ElementController to take care of it for now.
		editDialog(pElement);
	}
	/** Pops the options window */
	private void showOptions() {
		final Options options = new Options(getParent().getWindow(), tp.get("options"));
		
		// Empty
		
		options.open();
	}
	@Override
	protected void delete(int[] pTableIndices) {
		if (mEditController != null)
			for (int i : pTableIndices)
				mEditController.notifyRemoved(getElementAtIndex(i));
			
		
		super.delete(pTableIndices);
	}
	@Override
	protected void fillRow(TableItem pItem, Object[] pRow, Book pElement) {
		pRow[0] = pElement.getAuthor();
		pRow[1] = pElement.getName();
		pRow[2] = pElement.getGenre();
		pRow[3] = null;
		
		TableEditor editor = (TableEditor)pItem.getData(TABLEITEMDATA_EDITOR);
		Label label;
		
		if (editor == null) {
			editor = new TableEditor(getPanel().getTable());
			label = new Label(getPanel().getTable(), SWT.NO_BACKGROUND);
		} else
			label = (Label)editor.getEditor();
		
		final TableEditor finalEditor = editor;
		
		label.setImage(getBar(pElement));
		
		editor.grabHorizontal = true;
		editor.grabVertical = true;
		editor.setEditor(label, pItem, 3 + COLUMN_INDEX_OFFSET);
		
		pItem.addDisposeListener(new DisposeListener() {
			@Override
			public void widgetDisposed(DisposeEvent pE) {
				finalEditor.getEditor().dispose();
			}
		});
		
		pItem.setData(TABLEITEMDATA_EDITOR, editor);
	}
	private Image getBar(Book pElement) {
		if (mBarCreator == null)
			mBarCreator = new BarCreator(getParent().getCore().getDisplay(), 16, mRatingColumn.getTableColumn().getWidth(), RATING_MIN, RATING_MAX);

		Image image;
		if (pElement.getRating() >= 0)
			image = mBarCreator.getBar(pElement.getRating());
		else
			image = mBarCreator.getBar(0);
		
		return image;
	}
	@Override
	protected void initColumns() {
		String nameOrderString = "lower(author.surname) %1$s, lower(author.firstName) %1$s, case when substring(lower(name), 1, 4) = 'the ' then substring(lower(name), 5) else lower(name) end";

		new Column(0, tp.get("edit.author") + ":", 300, "order by " + nameOrderString + " %1$s", Order.asc);
		new Column(1, tp.get("edit.name") + ":", 300, "order by case when substring(lower(name), 1, 4) = 'the ' then substring(lower(name), 5) else lower(name) end %1$s, lower(author.surname) %1$s, lower(author.firstName) %1$s", Order.asc);
		new Column(2, tp.get("edit.genre") + ":", 160, "order by lower(genre.name) %1$s, " + nameOrderString + " asc", Order.asc);
		mRatingColumn = new Column(3, tp.get("edit.rating") + ":", 190, "order by rating %1$s, " + nameOrderString + " asc", Order.desc);
		
		mRatingColumn.getTableColumn().addControlListener(new ControlAdapter() {
			public void controlResized(ControlEvent pE) {
				mBarCreator.setWidth(mRatingColumn.getTableColumn().getWidth());

				for (TableItem item : getPanel().getTable().getItems()) {
					TableEditor editor = (TableEditor)item.getData(TABLEITEMDATA_EDITOR);
					Label label = (Label)editor.getEditor();
					
					label.setImage(getBar((Book)item.getData(TABLEITEMDATA_ELEMENT)));
				}
			}
		});
	}
	
	private Column mRatingColumn;
	
	@Override
	protected Book getNewInstance() {
		try {
			return Book.class.newInstance();
		} catch (Exception e) {
			if (e instanceof IllegalAccessException || e instanceof InstantiationException)
				logger.warning("BookController failed to create a new instance of Book.");
			else 
				e.printStackTrace();

			return null;
		}
	}
	@Override
	protected String getSearchQuery() {
		return "where lower(name) like '%%%1$s%%' or lower(genre.name) like '%%%1$s%%' or lower(location.name) like '%%%1$s%%'";
	}
	
	private static Logger logger = new Logger(BookController.class);
	
	public static final String TABLEITEMDATA_EDITOR = "editor";
	public static final String PREFS_SHOWRELEASEFIELDS = "showReleaseFields";
	
	private BookEditController mEditController;
	private BookViewController mViewController;
	private static BarCreator mBarCreator;
}